package cn.lingyangwl.agile.plugin.file.preview.service.impl;

import cn.lingyangwl.framework.core.response.Resp;
import cn.lingyangwl.framework.core.response.RetOps;
import cn.lingyangwl.framework.tool.core.exception.BizException;
import cn.lingyangwl.agile.plugin.file.preview.config.ConfigConstants;
import cn.lingyangwl.agile.plugin.file.preview.filter.BaseUrlFilter;
import cn.lingyangwl.agile.plugin.file.preview.model.FileAttribute;
import cn.lingyangwl.agile.plugin.file.preview.model.FilePreviewRS;
import cn.lingyangwl.agile.plugin.file.preview.service.FileHandlerService;
import cn.lingyangwl.agile.plugin.file.preview.service.FilePreview;
import cn.lingyangwl.agile.plugin.file.preview.service.OfficeToPdfService;
import cn.lingyangwl.agile.plugin.file.preview.utils.DownloadUtils;
import lombok.extern.slf4j.Slf4j;
import org.jodconverter.core.office.OfficeException;
import cn.lingyangwl.agile.plugin.file.preview.utils.OfficeUtils;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;

import java.net.URLEncoder;
import java.util.List;

/**
 * 处理office文件
 *
 * @author shenguangyang
 * @since 1.0.0
 */
@Slf4j
@Service
public class OfficeFilePreviewImpl implements FilePreview {

    public static final String OFFICE_PREVIEW_TYPE_IMAGE = "image";
    public static final String OFFICE_PREVIEW_TYPE_ALL_IMAGES = "allImages";
    private static final String FILE_DIR = ConfigConstants.getFileDir();

    private final FileHandlerService fileHandlerService;
    private final OfficeToPdfService officeToPdfService;
    private final OtherFilePreviewImpl otherFilePreview;

    public OfficeFilePreviewImpl(FileHandlerService fileHandlerService, OfficeToPdfService officeToPdfService, OtherFilePreviewImpl otherFilePreview) {
        this.fileHandlerService = fileHandlerService;
        this.officeToPdfService = officeToPdfService;
        this.otherFilePreview = otherFilePreview;
    }

    @Override
    public FilePreviewRS filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
        try {
            // 预览Type，参数传了就取参数的，没传取系统默认
            String officePreviewType = fileAttribute.getOfficePreviewType();
            String baseUrl = BaseUrlFilter.getBaseUrl();
            String suffix = fileAttribute.getSuffix();
            String fileName = fileAttribute.getName();
            String filePassword = fileAttribute.getFilePassword();
            String userToken = fileAttribute.getUserToken();
            boolean isHtml = suffix.equalsIgnoreCase("xls") || suffix.equalsIgnoreCase("xlsx") || suffix.equalsIgnoreCase("csv");
            String pdfName = fileName.substring(0, fileName.lastIndexOf(".") + 1) + (isHtml ? "html" : "pdf");
            String cacheFileName = userToken == null ? pdfName : userToken + "_" + pdfName;
            String outFilePath = FILE_DIR + cacheFileName;
            if ( !fileHandlerService.listConvertedFiles().containsKey(pdfName) || !ConfigConstants.isCacheEnabled()) {
                // 下载远程文件到本地，如果文件在本地已存在不会重复下载
                Resp<String> response = DownloadUtils.downLoad(fileAttribute, fileName);
                if (!RetOps.of(response).isSuccess()) {
                    throw new BizException(response.getMsg());
                }
                String filePath = response.getData();

                /*
                 * 1. 缓存判断-如果文件已经进行转换过，就直接返回，否则执行转换
                 * 2. 缓存判断-加密文件基于userToken进行缓存，如果没有就不缓存
                 */
                boolean isCached = false;
                boolean isUseCached = false;
                boolean isPwdProtectedOffice = false;
                if (ConfigConstants.isCacheEnabled()) {
                    // 全局开启缓存
                    isUseCached = true;
                    if (fileHandlerService.listConvertedFiles().containsKey(cacheFileName)) {
                        // 存在缓存
                        isCached = true;
                    }
                    if (OfficeUtils.isPwdProtected(filePath)) {
                        isPwdProtectedOffice = true;
                        if (!StringUtils.hasLength(userToken)) {
                            // 不缓存没有userToken的加密文件
                            isUseCached = false;
                        }
                    }
                } else {
                    isPwdProtectedOffice = OfficeUtils.isPwdProtected(filePath);
                }

                if (!isCached) {
                    // 没有缓存执行转换逻辑
                    if (isPwdProtectedOffice && !StringUtils.hasLength(filePassword)) {
                        // 加密文件需要密码
                        model.addAttribute("needFilePassword", true);
                        return FilePreviewRS.builder().type(EXEL_FILE_PREVIEW_PAGE).build();
                    } else {
                        if (StringUtils.hasText(outFilePath)) {
                            try {
                                officeToPdfService.openOfficeToPDF(filePath, outFilePath, fileAttribute);
                            } catch (OfficeException e) {
                                if (isPwdProtectedOffice && !OfficeUtils.isCompatible(filePath, filePassword)) {
                                    // 加密文件密码错误，提示重新输入
                                    model.addAttribute("needFilePassword", true);
                                    model.addAttribute("filePasswordError", true);
                                    return FilePreviewRS.builder().type(EXEL_FILE_PREVIEW_PAGE).build();
                                }
                                throw new BizException("抱歉，该文件版本不兼容，文件版本错误。");
                            }

                            if (isHtml) {
                                // 对转换后的文件进行操作(改变编码方式)
                                fileHandlerService.doActionConvertedFile(outFilePath);
                            }
                            if (isUseCached) {
                                // 加入缓存
                                fileHandlerService.addConvertedFile(cacheFileName, fileHandlerService.getRelativePath(outFilePath));
                            }
                        }
                    }
                }
            }
            if (!isHtml && baseUrl != null && (OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) || OFFICE_PREVIEW_TYPE_ALL_IMAGES.equals(officePreviewType))) {
                String previewType = getPreviewType(model, fileAttribute, officePreviewType, baseUrl, cacheFileName, outFilePath, fileHandlerService, OFFICE_PREVIEW_TYPE_IMAGE, otherFilePreview);
                return FilePreviewRS.builder().type(previewType).build();
            }
            cacheFileName =  URLEncoder.encode(cacheFileName, "utf-8").replaceAll("\\+", "%20");
            model.addAttribute("pdfUrl", cacheFileName);

            String type = isHtml ? EXEL_FILE_PREVIEW_PAGE : PDF_FILE_PREVIEW_PAGE;
            return FilePreviewRS.builder().type(type).build();
        } catch (Exception e) {
            log.error("error: ", e);
            throw new BizException("预览失败");
        }
    }

    static String getPreviewType(Model model, FileAttribute fileAttribute, String officePreviewType, String baseUrl, String pdfName, String outFilePath, FileHandlerService fileHandlerService, String officePreviewTypeImage, OtherFilePreviewImpl otherFilePreview) {
        String suffix = fileAttribute.getSuffix();
        boolean isPPT = suffix.equalsIgnoreCase("ppt") || suffix.equalsIgnoreCase("pptx");
        List<String> imageUrls = fileHandlerService.pdf2jpg(outFilePath, pdfName, baseUrl);
        if (imageUrls == null || imageUrls.size() < 1) {
            return otherFilePreview.notSupportedFile(model, fileAttribute, "office转图片异常，请联系管理员");
        }
        model.addAttribute("imgurls", imageUrls);
        model.addAttribute("currentUrl", imageUrls.get(0));
        if (officePreviewTypeImage.equals(officePreviewType)) {
            // PPT 图片模式使用专用预览页面
            return (isPPT ? PPT_FILE_PREVIEW_PAGE : OFFICE_PICTURE_FILE_PREVIEW_PAGE);
        } else {
            return PICTURE_FILE_PREVIEW_PAGE;
        }
    }

}
